﻿using DynamicExpresso;
using EF6Query.DBModel;
using EF6Query.Models;
using EF6Query.Models.Common;
using EF6Query.Models.Req;
using ExpressionBuilder.Generics;
using ExpressionBuilder.Helpers;
using ExpressionBuilder.Operations;

namespace EF6Query.QueryService
{
    public class ProductService
    {
        private static List<Product> Products = new()
        {
            Product.CreateObject(1,"实验室标样",new DateTime(2021,12,29,22,43,49),new DateTime (2021,12,29,23,43,51)),
            Product.CreateObject(2,"品样标管",new DateTime(2021,12,29,22,44,17),new DateTime (2021,12,29,22,44,19)),
            Product.CreateObject(4,"产品4",new DateTime(2022,1,21,21,50,52),new DateTime (2022,1,21,21,50,52)),
            Product.CreateObject(5,"产品5",new DateTime(2023,8,25,12,16,19),new DateTime (2023,8,25,12,16,19)),
        };
        private static List<ProductColor> ProductColors = new()
        {
            ProductColor.CreateObject(9,"测试色号2",2,2,"色号2的描述",new DateTime(2021,12,29,22,43,49),new DateTime(2021,12,29,22,43,49)),
              ProductColor.CreateObject(10,"测试色号1",2,1,"色号1的描述",new DateTime(2022,1,18,22,43,49),new DateTime(2022,1,18,22,43,49)),
                ProductColor.CreateObject(12,"测试色号4",2,4,"色号4的描述",new DateTime(2023,8,25,22,43,49),new DateTime(2023,8,25,22,43,49)),
                  ProductColor.CreateObject(13,"测试色号5",2,5,"色号5的描述",new DateTime(2023,8,25,22,43,49),new DateTime(2023, 8, 25,22,43,49)),
        };


        private OperationHelper operationHelper = new OperationHelper();
        public List<ProductView> ProductList()
        {
            // using var db = DBContext.CreateContext();
            var product = Products.AsQueryable();
            var productColor = ProductColors.AsQueryable();
            return (from p in product
                    join pc in productColor on p.ID equals pc.Productld
                    select new ProductView
                    {
                        ID = p.ID,
                        ProductName = p.ProductName,
                        ColorName = pc.ColorName,
                        ColorDesc = pc.ColorDesc,
                        CreateTime = p.CreateTime,
                    }).ToList();
        }


        public List<ProductView> ExpressionBuilderProductList(ExpressionBuilderRequest requests)
        {
            //using var db = DBContext.CreateContext();
            var product = Products.AsQueryable();
            var productColor = ProductColors.AsQueryable();
            FifterQuery(requests, ref product, ref productColor);
            var result = (from p in product
                          join pc in productColor on p.ID equals pc.Productld
                          select new ProductView
                          {
                              ID = p.ID,
                              ProductName = p.ProductName,
                              ColorName = pc.ColorName,
                              ColorDesc = pc.ColorDesc,
                              CreateTime = p.CreateTime,
                          });

            return result.ToList();
        }

        private void FifterQuery(ExpressionBuilderRequest requests, ref IQueryable<Product> product, ref IQueryable<ProductColor> productColor)
        {
            foreach (var request in requests.ExpressionBuilders)
            {
                if (request != null &&
                                   !string.IsNullOrEmpty(request.TableName) &&
                                    !string.IsNullOrEmpty(request.Condition) &&
                                    !string.IsNullOrEmpty(request.PropertyName) &&
                                    !string.IsNullOrEmpty(request.Value1))
                {
                    if (request.TableName == "Product")
                    {
                        Filter<Product> filter = new Filter<Product>();
                        var value1 = new DBEntityType().GetValue(request.TableName, request.PropertyName, request.Value1);
                        filter.By(request.PropertyName, operationHelper.GetOperationByName(request.Condition), value1);
                        product = product.Where(filter);
                    }
                    if (request.TableName == "ProductColor")
                    {
                        Filter<ProductColor> filter = new Filter<ProductColor>();
                        var value1 = new DBEntityType().GetValue(request.TableName, request.PropertyName, request.Value1);
                        filter.By(request.PropertyName, operationHelper.GetOperationByName(request.Condition), value1);
                        productColor = productColor.Where(filter);
                    }
                }
            }
        }


        /// <summary>
        /// 构建条件查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sourceQueryable"></param>
        /// <param name="expressionInfos"></param>
        /// <returns></returns>
        private IQueryable<T> BuildExpressionFifter<T>(IQueryable<T> sourceQueryable, List<ExpressionInfo> expressionInfos)
        where T : class
        {
            Filter<T> filter = new Filter<T>();
            foreach (var request in expressionInfos)
            {
                if (request != null
                    && !string.IsNullOrEmpty(request.TableName)
                    && !string.IsNullOrEmpty(request.Condition)
                    && !string.IsNullOrEmpty(request.PropertyName)
                    && !string.IsNullOrEmpty(request.Value1))
                {
                    var value1 = new DBEntityType().GetValue(request.TableName, request.PropertyName, request.Value1);
                    filter.By(request.PropertyName, operationHelper.GetOperationByName(request.Condition), value1);
                    if (string.IsNullOrEmpty(request.Value2))
                    {
                        var value2 = new DBEntityType().GetValue(request.TableName, request.PropertyName, request.Value2);
                        filter.By(request.PropertyName, operationHelper.GetOperationByName(request.Condition), value1, value2);
                    }
                }
            }
            return sourceQueryable.Where(filter);
        }



        public List<ProductView> ProductFifter(List<DynamicExpressionRequest> request)
        {
            //using var db = DBContext.CreateContext();

            var product = Products.AsQueryable();
            var productColor = ProductColors.AsQueryable();
            if (request != null)
            {
                foreach (var item in request)
                {
                    if (string.IsNullOrEmpty(item.Expression))
                        continue;
                    if (item.TableName == "Product")
                    {
                        Func<Product, bool> productDynamic = new Interpreter().ParseAsDelegate<Func<Product, bool>>(item.Expression, item.TableName);
                        product = product.Where(productDynamic).AsQueryable();
                        // product = product.DynamicFilter(item);
                    }
                    if (item.TableName == "ProductColor")
                    {
                        Func<ProductColor, bool> productDynamic = new Interpreter().ParseAsDelegate<Func<ProductColor, bool>>(item.Expression, item.TableName);
                        productColor = productColor.Where(productDynamic).AsQueryable();
                        //productColor = productColor.DynamicFilter(item);
                    }
                }
            }
            var result = (from p in product
                          join pc in productColor on p.ID equals pc.Productld
                          select new ProductView
                          {
                              ID = p.ID,
                              ProductName = p.ProductName,
                              ColorName = pc.ColorName
                          }).ToList();
            var query = (from p in product
                         join pc in productColor on p.ID equals pc.Productld
                         select new ProductView
                         {
                             ID = p.ID,
                             ProductName = p.ProductName,
                             ColorName = pc.ColorName,
                             ColorDesc = pc.ColorDesc,
                             CreateTime = p.CreateTime,
                         });
            return query.ToList();

        }



        private IQueryable<Product> FilterProduct<Product>(IQueryable<Product> queryable, List<DynamicExpressionRequest> request)
        {
            if (request != null && request.Any())
            {
                foreach (var expression in request)
                {
                    if (string.IsNullOrEmpty(expression.Expression) || string.IsNullOrEmpty(expression.TableName))
                        continue;
                    Console.WriteLine($"TableName: {expression.TableName} Expression:{expression.Expression}");
                    Func<Product, bool> dynamicWhere = new Interpreter().ParseAsDelegate<Func<Product, bool>>(expression.Expression, expression.TableName);
                    queryable = queryable.Where(dynamicWhere).AsQueryable();
                }
            }
            return queryable;
        }


        private static Func<T, bool> FilterDynamic<T>(DynamicExpressionRequest request)
        {
            Func<T, bool> dynamicWhere = null;
            if (request != null)
            {
                if (string.IsNullOrEmpty(request.Expression) && string.IsNullOrEmpty(request.TableName))
                {
                    var type = request.GetType();
                    dynamicWhere = new Interpreter().ParseAsDelegate<Func<T, bool>>(request.Expression, request.TableName);
                    return dynamicWhere;
                }
            }
            return (x) => true;
        }

        public void DynamicExpressionQueryTest()
        {
            //using (var db = DBContext.CreateContext())

            var product = Products.AsQueryable();
            string whereExpression = $"Product.ID ==1";
            Func<Product, bool> dynamicWhere = new Interpreter().ParseAsDelegate<Func<Product, bool>>(whereExpression, "Product");
            var result1 = product.Where(dynamicWhere).ToList();
            Console.WriteLine(result1?.FirstOrDefault()?.ProductName ?? "无数据");

            var request = new List<DynamicExpressionRequest>()
                {
                    new DynamicExpressionRequest(){ TableName ="p", Expression = "p.ID ==1" },
                };
            product = FilterProduct(product, request);
            var result2 = product.ToList();
            Console.WriteLine(result2?.FirstOrDefault()?.ProductName ?? "无数据");

            var productColor = ProductColors.AsQueryable();
            //var productV2 = Products.Where(x => x.ID == 1).AsQueryable();
            Filter<Product> filter = new Filter<Product>();
            filter.By("ID", Operation.EqualTo, 1);
            var productV2 = Products.Where(filter).AsQueryable();
            var result3 = (from p in productV2
                           join pc in productColor on p.ID equals pc.Productld
                           select new ProductView
                           {
                               ID = p.ID,
                               ProductName = p.ProductName,
                               ColorName = pc.ColorName
                           }).ToList();
            Console.WriteLine(result3?.FirstOrDefault()?.ProductName ?? "无数据");
            //var result = product.Where(x=>x.ProductName == "品管标样").ToList();

        }

        public void DynamicExpressionJoinQueryTest()
        {
            string productExpression = $"Product.ID >1";
            Func<Product, bool> productDynamic = new Interpreter().ParseAsDelegate<Func<Product, bool>>(productExpression, "Product");

            string productColorExpression = $"ProductColor.ID > 10";
            Func<ProductColor, bool> productColorDynamic = new Interpreter().ParseAsDelegate<Func<ProductColor, bool>>(productColorExpression, "ProductColor");
            //using var db = DBContext.CreateContext();

            //var products = Products.Where(productDynamic).ToList();
            //var productColors = ProductColors.Where(productColorDynamic).ToList();
            //Console.WriteLine($"productConut:{products.Count}+productColorCount:{productColors.Count}");

            var product = Products.Where(productDynamic).AsQueryable();
            var productColor = ProductColors.Where(productColorDynamic).AsQueryable();

            var result = (from p in product
                          join pc in productColor on p.ID equals pc.Productld
                          select new ProductView
                          {
                              ID = p.ID,
                              ProductName = p.ProductName,
                              ColorName = pc.ColorName
                          }).ToList();
            Console.WriteLine($"QueryConut:{result.Count}");

        }





        public void insetData()
        {

        }
    }
}
